package org;

import java.awt.BorderLayout;
import java.awt.Component;
import java.io.IOException;
import java.net.URL;
import java.util.List;

import javax.media.CannotRealizeException;
import javax.media.Codec;
import javax.media.ConfigureCompleteEvent;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.EndOfMediaEvent;
import javax.media.Manager;
import javax.media.NoPlayerException;
import javax.media.PrefetchCompleteEvent;
import javax.media.Processor;
import javax.media.RealizeCompleteEvent;
import javax.media.ResourceUnavailableEvent;
import javax.media.Time;
import javax.media.UnsupportedPlugInException;
import javax.media.control.TrackControl;
import javax.media.format.VideoFormat;
import javax.swing.JPanel;

public class MediaPanel extends JPanel implements ControllerListener

{

    Processor processor = null;

    Component visualComponent = null;

    Component controlPanel = null;

    List<Codec> effects = null;

    Object waitSync = new Object();

    boolean stateTransitionOK = true;
    
    boolean showControlPanel = true;

    /**
     * .
     *<BR><pre>
     *<b>Algorithme : </b>
     *DEBUT
     *    
     *FIN</pre>
     *
     * @param showControlPanel
     */
    public MediaPanel(boolean showControlPanel)
    {
        this();
        this.showControlPanel = showControlPanel;
    }

    public MediaPanel()
    {

        Manager.setHint(Manager.LIGHTWEIGHT_RENDERER, true);

        setLayout(new BorderLayout());

    }

    public MediaPanel(URL mediaURL)
    {

        this();

        open(mediaURL);

    }

    public void setEffects(List<Codec> aEffects)
    {

        effects = aEffects;

    }

    public List<Codec> getEffects()
    {

        return effects;

    }

    public void open(URL mediaURL)
    {

        try
        {

            if (processor != null)
            {

                processor.stop();

                processor.close();

                remove(visualComponent);

                remove(controlPanel);

            }

            // create a player to play the media specified in the URL

            processor = Manager.createProcessor(mediaURL);

            processor.addControllerListener(this);

            processor.configure();

            if (!waitForState(Processor.Configured))
            {

                throw new Exception("Failed to configure the processor.");

            }

            processor.setContentDescriptor(null);

            // Obtain the track controls.

            TrackControl tc[] = processor.getTrackControls();

            if (tc == null)
            {

                throw new Exception("Failed to obtain track controls from the processor.");

            }

            // Search for the track control for the video track.

            TrackControl videoTrack = null;

            for (int i = 0; i < tc.length; i++)
            {

                if (tc[i].getFormat() instanceof VideoFormat)
                {

                    videoTrack = tc[i];

                    break;

                }

            }

            if (videoTrack == null)
            {

                throw new Exception("The input media does not contain a video track.");

            }

            System.err.println("Video format: " + videoTrack.getFormat());

            // Instantiate and set the frame access codec to the data flow path.

            try
            {

                if (effects != null && !effects.isEmpty())
                    videoTrack.setCodecChain((Codec[]) effects.toArray(new Codec[effects.size()]));

            }
            catch (UnsupportedPlugInException e)
            {

                throw new Exception("The processor does not support effects.");

            }

            processor.prefetch();

            if (!waitForState(Processor.Prefetched))
            {

                throw new Exception("Failed to realize the processor");

            }

            // get the components for the video and the playback controls

            visualComponent = processor.getVisualComponent();

            controlPanel = processor.getControlPanelComponent();

            setLayout(new BorderLayout());

            if (visualComponent != null)

                add(visualComponent, BorderLayout.CENTER); // add video component

            if (showControlPanel && controlPanel != null){

                add(controlPanel, BorderLayout.SOUTH); // add controls
            } else{
                if (processor.getState() != Processor.Started)
                processor.start();
            }

            validate();

        }
        catch (NoPlayerException noPlayerException)
        {

            System.err.println("No media player found");

        }
        catch (CannotRealizeException cannotRealizeException)
        {

            System.err.println("Could not realize media player");

        }
        catch (IOException iOException)
        {

            System.err.println("Error reading from the source");

        }
        catch (Exception e)
        {

            System.err.println(e.getMessage());

        }

    }

    /**

     * Controller Listener.

     */

    public void controllerUpdate(ControllerEvent evt)
    {

        if (evt instanceof ConfigureCompleteEvent ||

        evt instanceof RealizeCompleteEvent ||

        evt instanceof PrefetchCompleteEvent)
        {

            synchronized (waitSync)
            {

                stateTransitionOK = true;

                waitSync.notifyAll();

            }

        }
        else if (evt instanceof ResourceUnavailableEvent)
        {

            synchronized (waitSync)
            {

                stateTransitionOK = false;

                waitSync.notifyAll();

            }

        }
        else if (evt instanceof EndOfMediaEvent)
        {
        	System.out.println("Processor EndOfMedia");
			processor.setMediaTime(new Time(0));
			processor.start();
			
            // processor.close();

            // System.exit(0);

        }

    }

    /**

     * Block until the processor has transitioned to the given state.

     * Return false if the transition failed.

     */

    boolean waitForState(int state)
    {

        synchronized (waitSync)
        {

            try
            {

                while (processor.getState() != state && stateTransitionOK)

                    waitSync.wait();

            }
            catch (Exception e)
            {
            }

        }

        return stateTransitionOK;

    }

}
